#!/system/bin/sh

export PATH="/data/adb/magisk:/data/adb/ksu/bin:/data/adb/ap/bin:$PATH:/data/data/com.termux/files/usr/bin"

scripts=$(realpath $0)
scripts_dir=$(dirname ${scripts})

source ${scripts_dir}/box.config
mark_id="16777216/16777216"
table_id="2024"
# routing_mark="233"

log() {
  export TZ=Asia/Shanghai
  now=$(date +"[%Y-%m-%d %H:%M:%S %Z]")
  case $1 in
    Info)
      [ -t 1 ] && echo -e "\033[1;32m${now} [Info]: $2\033[0m" || echo "${now} [Info]: $2"
      ;;
    Warn)
      [ -t 1 ] && echo -e "\033[1;33m${now} [Warn]: $2\033[0m" || echo "${now} [Warn]: $2"
      ;;
    Error)
      [ -t 1 ] && echo -e "\033[1;31m${now} [Error]: $2\033[0m" || echo "${now} [Error]: $2"
      ;;
    *)
      [ -t 1 ] && echo -e "\033[1;30m${now} [$1]: $2\033[0m" || echo "${now} [$1]: $2"
      ;;
  esac
}

uid_list=()
find_packages_uid() {
  for user_package in ${user_packages_list[@]} ; do
    user=$(echo ${user_package} | awk -F ':' '{print $1}')
    package=$(echo ${user_package} | awk -F ':' '{print $2}')
    uid="$(awk '{if($1=="'${package}'"){print $2}}' /data/system/packages.list)"
    if [[ -n "${uid}" ]]; then
      uid_list[${#uid_list[@]}]=$(expr ${user} \* "100000" + ${uid})
    fi
  done
}

probe_user_group() {
  if bin_pid=$(busybox pidof ${bin_name}) ; then
    box_user=$(stat -c %U /proc/${bin_pid})
    box_group=$(stat -c %G /proc/${bin_pid})
    return 0
  else
    box_user=$(echo ${box_user_group} | awk -F ':' '{print $1}')
    box_group=$(echo ${box_user_group} | awk -F ':' '{print $2}')
    return 1
  fi
}

start_redirect() {
  ${iptables} -t nat -N BOX_EXTERNAL
  ${iptables} -t nat -F BOX_EXTERNAL
  ${iptables} -t nat -N BOX_LOCAL
  ${iptables} -t nat -F BOX_LOCAL

  if [ "${bin_name}" = "clash" ] ; then
    ${iptables} -t nat -A BOX_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports ${clash_dns_port}
    ${iptables} -t nat -A BOX_LOCAL -p udp --dport 53 -j REDIRECT --to-ports ${clash_dns_port}
    ${iptables} -t nat -A BOX_EXTERNAL -d ${clash_fake_ip_range} -p icmp -j DNAT --to-destination 127.0.0.1
    ${iptables} -t nat -A BOX_LOCAL -d ${clash_fake_ip_range} -p icmp -j DNAT --to-destination 127.0.0.1
#  else
#    Other types of inbound should be added here to receive DNS traffic instead of sniffing
#    ${iptables} -t nat -A BOX_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports ${redir_port}
#    ${iptables} -t nat -A BOX_LOCAL -p udp --dport 53 -j REDIRECT --to-ports ${redir_port}
  fi

  for subnet in ${intranet[@]} ; do
    ${iptables} -t nat -A BOX_EXTERNAL -d ${subnet} -j RETURN
    ${iptables} -t nat -A BOX_LOCAL -d ${subnet} -j RETURN
  done

  ${iptables} -t nat -A BOX_EXTERNAL -p tcp -i lo -j REDIRECT --to-ports ${redir_port}

  if [ "${ap_list}" != "" ] ; then
    for ap in ${ap_list[@]} ; do
      ${iptables} -t nat -A BOX_EXTERNAL -p tcp -i ${ap} -j REDIRECT --to-ports ${redir_port}
    done
    log Info "${ap_list[*]} transparent proxy."
  fi

  ${iptables} -t nat -I PREROUTING -j BOX_EXTERNAL


  ${iptables} -t nat -I BOX_LOCAL -m owner --uid-owner ${box_user} --gid-owner ${box_group} -j RETURN

  if [ "${ignore_out_list}" != "" ] ; then
    for ignore in ${ignore_out_list[@]} ; do
      ${iptables} -t nat -I BOX_LOCAL -o ${ignore} -j RETURN
    done
    log Info "${ignore_out_list[*]} ignore transparent proxy."
  fi

  if [ "${proxy_mode}" = "blacklist" ] ; then
    if [ "${uid_list}" = "" ] ; then
      # Route Everything
      ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports ${redir_port}
      log Info "transparent proxy for all apps."
    else
      # Bypass apps
      for appid in ${uid_list[@]} ; do
        ${iptables} -t nat -I BOX_LOCAL -m owner --uid-owner ${appid} -j RETURN
      done
      # Allow !app
      ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports ${redir_port}
      log Info "proxy mode: ${proxy_mode}, ${user_packages_list[*]} no transparent proxy."
    fi
    if [ "${gid_list}" != "" ] ; then
      # Bypass gids
      for gid in ${gid_list[@]} ; do
        ${iptables} -t nat -I BOX_LOCAL -m owner --gid-owner ${gid} -j RETURN
      done
      log Info "proxy mode: ${proxy_mode}, GID ${gid_list[*]} no transparent proxy."
    fi
  elif [ "${proxy_mode}" = "whitelist" ] ; then
    if [ "${uid_list}" != "" ] ; then
      # Route apps to Box
      for appid in ${uid_list[@]} ; do
        ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner ${appid} -j REDIRECT --to-ports ${redir_port}
      done
      ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j REDIRECT --to-ports ${redir_port}
      ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j REDIRECT --to-ports ${redir_port}
      log Info "proxy mode: ${proxy_mode}, ${user_packages_list[*]} transparent proxy."
    fi
    if [ "${gid_list}" != "" ] ; then
      # Route gids to Box
      for gid in ${gid_list[@]} ; do
        ${iptables} -t nat -A BOX_LOCAL -p tcp -m owner --gid-owner ${gid} -j REDIRECT --to-ports ${redir_port}
      done
      log Info "proxy mode: ${proxy_mode}, GID ${gid_list[*]} transparent proxy."
    fi
  else
    log Warn "proxy mode: ${proxy_mode} error."
    # Route Everything
    ${iptables} -t nat -A BOX_LOCAL -p tcp -j REDIRECT --to-ports ${redir_port}
    log Info "transparent proxy for all apps."
  fi

  ${iptables} -t nat -I OUTPUT -j BOX_LOCAL

  ${iptables} -A OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner ${box_user} --gid-owner ${box_group} -m tcp --dport ${redir_port} -j REJECT
}

stop_redirect() {
  ${iptables} -t nat -D PREROUTING -j BOX_EXTERNAL

  ${iptables} -t nat -D OUTPUT -j BOX_LOCAL

  ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner ${box_user} --gid-owner ${box_group} -m tcp --dport ${redir_port} -j REJECT
  ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner 0 --gid-owner 3005 -m tcp --dport ${redir_port} -j REJECT


  ${iptables} -t nat -F BOX_EXTERNAL
  ${iptables} -t nat -X BOX_EXTERNAL
  ${iptables} -t nat -F BOX_LOCAL
  ${iptables} -t nat -X BOX_LOCAL
}

start_tproxy() {
  if [ "${iptables}" = "ip6tables -w 100" ] ; then
    ip -6 rule add fwmark ${mark_id} table ${table_id} pref ${table_id}
    ip -6 route add local default dev lo table ${table_id}
  else
    ip rule add fwmark ${mark_id} table ${table_id} pref ${table_id}
    ip route add local default dev lo table ${table_id}
  fi

  ${iptables} -t mangle -N BOX_EXTERNAL
  ${iptables} -t mangle -F BOX_EXTERNAL

  # Bypass box itself
  # ${iptables} -t mangle -A BOX_EXTERNAL -m mark --mark ${routing_mark} -j RETURN

  # Bypass other if
  # Notice: Some interface is named with r_ / oem / nm_ / qcom_
  # It might need more complicated solution.
  # ${iptables} -t mangle -A BOX_EXTERNAL -i rmnet_data+ -j RETURN
  # ${iptables} -t mangle -A BOX_EXTERNAL -i ccmni+ -j RETURN

  # Skip traffic already handled by TProxy
  # If the interface of the default route has a public IPv4 or IPv6 address assigned by the ISP, omitting these rules will result in abnormal proxy behavior for local traffic, which may cause the entire network to run slower
  # ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -m socket --transparent -j MARK --set-xmark ${mark_id}
  # ${iptables} -t mangle -A BOX_EXTERNAL -p udp -m socket --transparent -j MARK --set-xmark ${mark_id}
  # ${iptables} -t mangle -A BOX_EXTERNAL -m socket -j RETURN

  if [ "${bin_name}" = "clash" ] || [ "${bin_name}" = "hysteria" ] ; then
    ${iptables} -t mangle -A BOX_EXTERNAL -p tcp --dport 53 -j RETURN
    ${iptables} -t mangle -A BOX_EXTERNAL -p udp --dport 53 -j RETURN
  else
    # Route DNS request to Box
    ${iptables} -t mangle -A BOX_EXTERNAL -p tcp --dport 53 -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${mark_id}
    ${iptables} -t mangle -A BOX_EXTERNAL -p udp --dport 53 -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${mark_id}
  fi
  # Bypass intranet
  # Run `su -c 'zcat /proc/config.gz | grep -i addrtype'` to check compatibility
  # ${iptables} -t mangle -A BOX_EXTERNAL -m addrtype --dst-type LOCAL -j RETURN
  if [ "${iptables}" = "ip6tables -w 100" ] ; then
    for subnet6 in ${intranet6[@]} ; do
      ${iptables} -t mangle -A BOX_EXTERNAL -d ${subnet6} -j RETURN
    done
  else
    for subnet in ${intranet[@]} ; do
      ${iptables} -t mangle -A BOX_EXTERNAL -d ${subnet} -j RETURN
    done
  fi

  ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -i lo -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${mark_id}
  ${iptables} -t mangle -A BOX_EXTERNAL -p udp -i lo -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${mark_id}

  # Allow ap interface
  # Notice: Old android device may only have one wlan interface.
  # Some new android device have multiple wlan interface like wlan0(for internet), wlan1(for AP).
  if [ "${ap_list}" != "" ] ; then
    for ap in ${ap_list[@]} ; do
      ${iptables} -t mangle -A BOX_EXTERNAL -p tcp -i ${ap} -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${mark_id}
      ${iptables} -t mangle -A BOX_EXTERNAL -p udp -i ${ap} -j TPROXY --on-port ${tproxy_port} --tproxy-mark ${mark_id}
    done
    log Info "${ap_list[*]} transparent proxy."
  fi

  ${iptables} -t mangle -I PREROUTING -j BOX_EXTERNAL


  ${iptables} -t mangle -N BOX_LOCAL
  ${iptables} -t mangle -F BOX_LOCAL

  # Bypass box itself
  ${iptables} -t mangle -A BOX_LOCAL -m owner --uid-owner ${box_user} --gid-owner ${box_group} -j RETURN
  # ${iptables} -t mangle -A BOX_LOCAL -m mark --mark ${routing_mark} -j RETURN

  # Bypass ignored interfaces
  if [ "${ignore_out_list}" != "" ] ; then
    for ignore in ${ignore_out_list[@]} ; do
      ${iptables} -t mangle -A BOX_LOCAL -o ${ignore} -j RETURN
    done
    log Info "${ignore_out_list[*]} ignore transparent proxy."
  fi

  if [ "${bin_name}" = "clash" ] || [ "${bin_name}" = "hysteria" ] ; then
    ${iptables} -t mangle -A BOX_LOCAL -p tcp --dport 53 -j RETURN
    ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j RETURN
  else
    # Route DNS request to Box
    ${iptables} -t mangle -A BOX_LOCAL -p tcp --dport 53 -j MARK --set-xmark ${mark_id}
    ${iptables} -t mangle -A BOX_LOCAL -p udp --dport 53 -j MARK --set-xmark ${mark_id}
  fi
  # Bypass intranet
  # ${iptables} -t mangle -A BOX_LOCAL -m addrtype --dst-type LOCAL -j RETURN
  if [ "${iptables}" = "ip6tables -w 100" ] ; then
    for subnet6 in ${intranet6[@]} ; do
      ${iptables} -t mangle -A BOX_LOCAL -d ${subnet6} -j RETURN
    done
  else
    for subnet in ${intranet[@]} ; do
      ${iptables} -t mangle -A BOX_LOCAL -d ${subnet} -j RETURN
    done
  fi

  # Disable kernel
  # ${iptables} -t mangle -A BOX_LOCAL -m owner ! --uid 0-99999999 -j DROP

  if [ "${proxy_mode}" = "blacklist" ] ; then
    if [ "${uid_list}" = "" ] ; then
      # Route Everything
      ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark ${mark_id}
      ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark ${mark_id}
      log Info "transparent proxy for all apps."
    else
      # Bypass apps
      for appid in ${uid_list[@]} ; do
        ${iptables} -t mangle -A BOX_LOCAL -m owner --uid-owner ${appid} -j RETURN
      done
      # Allow !app
      ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark ${mark_id}
      ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark ${mark_id}
      log Info "proxy mode: ${proxy_mode}, ${user_packages_list[*]} no transparent proxy."
    fi
    if [ "${gid_list}" != "" ] ; then
      # Bypass gids
      for gid in ${gid_list[@]} ; do
        ${iptables} -t mangle -A BOX_LOCAL -m owner --gid-owner ${gid} -j RETURN
      done
      log Info "proxy mode: ${proxy_mode}, GID ${gid_list[*]} no transparent proxy."
    fi
  elif [ "${proxy_mode}" = "whitelist" ] ; then
    if [ "${uid_list}" != "" ] ; then
      # Route apps to Box
      for appid in ${uid_list[@]} ; do
        ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner ${appid} -j MARK --set-xmark ${mark_id}
        ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner ${appid} -j MARK --set-xmark ${mark_id}
      done
      ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 0 -j MARK --set-xmark ${mark_id}
      ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 0 -j MARK --set-xmark ${mark_id}
      # Route dnsmasq to Box
      ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --uid-owner 1052 -j MARK --set-xmark ${mark_id}
      ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --uid-owner 1052 -j MARK --set-xmark ${mark_id}
      log Info "proxy mode: ${proxy_mode}, ${user_packages_list[*]} transparent proxy."
    fi
    if [ "${gid_list}" != "" ] ; then
      # Route gids to Box
      for gid in ${gid_list[@]} ; do
        ${iptables} -t mangle -A BOX_LOCAL -p tcp -m owner --gid-owner ${gid} -j MARK --set-xmark ${mark_id}
        ${iptables} -t mangle -A BOX_LOCAL -p udp -m owner --gid-owner ${gid} -j MARK --set-xmark ${mark_id}
      done
      log Info "proxy mode: ${proxy_mode}, GID ${gid_list[*]} transparent proxy."
    fi
  else
    log Warn "proxy mode: ${proxy_mode} error."
    # Route Everything
    ${iptables} -t mangle -A BOX_LOCAL -p tcp -j MARK --set-xmark ${mark_id}
    ${iptables} -t mangle -A BOX_LOCAL -p udp -j MARK --set-xmark ${mark_id}
    log Info "transparent proxy for all apps."
  fi

  ${iptables} -t mangle -I OUTPUT -j BOX_LOCAL


  ${iptables} -t mangle -N DIVERT
  ${iptables} -t mangle -F DIVERT

  ${iptables} -t mangle -A DIVERT -j MARK --set-xmark ${mark_id}
  ${iptables} -t mangle -A DIVERT -j ACCEPT

  ${iptables} -t mangle -I PREROUTING -p tcp -m socket -j DIVERT


  # This rule blocks local access to tproxy-port to prevent traffic loopback.
  if [ "${iptables}" = "ip6tables -w 100" ] ; then
    ${iptables} -A OUTPUT -d ::1 -p tcp -m owner --uid-owner ${box_user} --gid-owner ${box_group} -m tcp --dport ${tproxy_port} -j REJECT
  else
    ${iptables} -A OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner ${box_user} --gid-owner ${box_group} -m tcp --dport ${tproxy_port} -j REJECT
  fi


  if [ "${bin_name}" = "clash" ] && [ "${iptables}" = "iptables -w 100" ] ; then
    # android ip6tablses no nat table
    ${iptables} -t nat -N CLASH_DNS_EXTERNAL
    ${iptables} -t nat -F CLASH_DNS_EXTERNAL

    ${iptables} -t nat -A CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports ${clash_dns_port}

    ${iptables} -t nat -I PREROUTING -j CLASH_DNS_EXTERNAL


    ${iptables} -t nat -N CLASH_DNS_LOCAL
    ${iptables} -t nat -F CLASH_DNS_LOCAL

    ${iptables} -t nat -A CLASH_DNS_LOCAL -m owner --uid-owner ${box_user} --gid-owner ${box_group} -j RETURN

    ${iptables} -t nat -A CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports ${clash_dns_port}

    ${iptables} -t nat -I OUTPUT -j CLASH_DNS_LOCAL
  fi

  # Fix ICMP (ping), this does not guarantee that the ping result is valid (proxies such as clash do not support forwarding ICMP),
  # just that it returns a result, "--to-destination" can be set to a reachable address
  iptables -w 100 -t nat -A OUTPUT -d ${fake_ip_range_v4} -p icmp -j DNAT --to-destination 127.0.0.1
  iptables -w 100 -t nat -A PREROUTING -d ${fake_ip_range_v4} -p icmp -j DNAT --to-destination 127.0.0.1
  # ip6tables -w 100 -t nat -A OUTPUT -d ${fake_ip_range_v6} -p icmp -j DNAT --to-destination ::1
  # ip6tables -w 100 -t nat -A PREROUTING -d ${fake_ip_range_v6} -p icmp -j DNAT --to-destination ::1
}

stop_tproxy() {
  ip -6 rule del fwmark ${mark_id} table ${table_id} pref ${table_id}
  ip -6 route flush table ${table_id}
  ip rule del fwmark ${mark_id} table ${table_id} pref ${table_id}
  ip route flush table ${table_id}

  ${iptables} -t mangle -D PREROUTING -j BOX_EXTERNAL
    
  ${iptables} -t mangle -D PREROUTING -p tcp -m socket -j DIVERT

  ${iptables} -t mangle -D OUTPUT -j BOX_LOCAL

  ${iptables} -t mangle -F BOX_EXTERNAL
  ${iptables} -t mangle -X BOX_EXTERNAL

  ${iptables} -t mangle -F BOX_LOCAL
  ${iptables} -t mangle -X BOX_LOCAL

  ${iptables} -t mangle -F DIVERT
  ${iptables} -t mangle -X DIVERT

  if [ "${iptables}" = "ip6tables -w 100" ] ; then
    ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner ${box_user} --gid-owner ${box_group} -m tcp --dport ${tproxy_port} -j REJECT
    ${iptables} -D OUTPUT -d ::1 -p tcp -m owner --uid-owner 0 --gid-owner 3005 -m tcp --dport ${tproxy_port} -j REJECT
  else
    ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner ${box_user} --gid-owner ${box_group} -m tcp --dport ${tproxy_port} -j REJECT
    ${iptables} -D OUTPUT -d 127.0.0.1 -p tcp -m owner --uid-owner 0 --gid-owner 3005 -m tcp --dport ${tproxy_port} -j REJECT
  fi


  # android ip6tablses no nat table
  iptables="iptables -w 100"
  ${iptables} -t nat -D PREROUTING -j CLASH_DNS_EXTERNAL

  ${iptables} -t nat -D OUTPUT -j CLASH_DNS_LOCAL

  ${iptables} -t nat -F CLASH_DNS_EXTERNAL
  ${iptables} -t nat -X CLASH_DNS_EXTERNAL

  ${iptables} -t nat -F CLASH_DNS_LOCAL
  ${iptables} -t nat -X CLASH_DNS_LOCAL

  iptables -t nat -D OUTPUT -d ${fake_ip_range_v4} -p icmp -j DNAT --to-destination 127.0.0.1
  iptables -t nat -D PREROUTING -d ${fake_ip_range_v4} -p icmp -j DNAT --to-destination 127.0.0.1
  # ip6tables -t nat -D OUTPUT -d ${fake_ip_range_v6} -p icmp -j DNAT --to-destination ::1
  # ip6tables -t nat -D PREROUTING -d ${fake_ip_range_v6} -p icmp -j DNAT --to-destination ::1
}

disable_ipv6() {
  echo 0 > /proc/sys/net/ipv6/conf/all/accept_ra
  echo 0 > /proc/sys/net/ipv6/conf/wlan0/accept_ra
  echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6
  echo 1 > /proc/sys/net/ipv6/conf/default/disable_ipv6
  echo 1 > /proc/sys/net/ipv6/conf/wlan0/disable_ipv6
}

enable_ipv6() {
  echo 1 > /proc/sys/net/ipv6/conf/all/accept_ra
  echo 1 > /proc/sys/net/ipv6/conf/wlan0/accept_ra
  echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6
  echo 0 > /proc/sys/net/ipv6/conf/default/disable_ipv6
  echo 0 > /proc/sys/net/ipv6/conf/wlan0/disable_ipv6
}

if [ "${proxy_mode}" = "core" ] ; then
  iptables="iptables -w 100" && stop_tproxy >> /dev/null 2>&1
  iptables="ip6tables -w 100" && stop_tproxy >> /dev/null 2>&1
  iptables="iptables -w 100" && stop_redirect >> /dev/null 2>&1
  log Info "proxy_mode: ${proxy_mode}, disable transparent proxy."
  return 0
fi

case "$1" in
  enable)
    iptables="iptables -w 100" && stop_tproxy >> /dev/null 2>&1
    iptables="ip6tables -w 100" && stop_tproxy >> /dev/null 2>&1
    iptables="iptables -w 100" && stop_redirect >> /dev/null 2>&1
    sleep 1
    if ! probe_user_group ; then
      log Error "failed to check Box user group, please make sure ${bin_name} core is started."
      return 1
    fi
    find_packages_uid
    intranet[${#intranet[@]}]=$(ip address | grep -w inet | grep -v 127 | awk '{print $2}')
    if [ "${proxy_method}" = "TPROXY" ] ; then
      if (zcat /proc/config.gz | grep -q TPROXY) ; then
        log Info "use TPROXY:TCP+UDP."
        log Info "creating ip(6)tables transparent proxy rules."
        iptables="iptables -w 100"
        start_tproxy && log Info "create iptables transparent proxy rules done." || (log Error "create iptables transparent proxy rules failed." && stop_tproxy >> /dev/null 2>&1)
        if [ "${ipv6}" = "enable" ] ; then
          log Debug "use IPv6."
          enable_ipv6
          iptables="ip6tables -w 100"
          intranet6[${#intranet6[@]}]=$(ip address | grep -w inet6 | grep -v ::1 | grep -v fe80 | awk '{print $2}')
          start_tproxy && log Info "create ip6tables transparent proxy rules done." || (log Error "create ip6tables transparent proxy rules failed." && stop_tproxy >> /dev/null 2>&1)
        else
          disable_ipv6
          log Warn "disable IPv6."
        fi
      else
        log Warn "the device does not support TPROXY, please switch proxy_method."
        log Info "use REDIRECT:TCP."
        log Info "creating iptables transparent proxy rules."
        iptables="iptables -w 100"
        start_redirect && log Info "create iptables transparent proxy rules done." || (log Error "create iptables transparent proxy rules failed." && stop_redirect >> /dev/null 2>&1)
        [ "${ipv6}" = "enable" ] && enable_ipv6 && log Warn "enable IPv6." || (disable_ipv6 && log Warn "disable IPv6.")
      fi
    else
      [ "${proxy_method}" = "REDIRECT" ] && log Info "use REDIRECT:TCP." || log Info "use MIXED:TCP+TUN."
      log Info "creating iptables transparent proxy rules."
      iptables="iptables -w 100"
      start_redirect && log Info "create iptables transparent proxy rules done." || (log Error "create iptables transparent proxy rules failed." && stop_redirect >> /dev/null 2>&1)
      [ "${ipv6}" = "enable" ] && enable_ipv6 && log Warn "enable IPv6." || (disable_ipv6 && log Warn "disable IPv6.")
    fi
    ;;
  disable)
    log Warn "cleaning up ip(6)tables transparent proxy rules."
    probe_user_group
    iptables="iptables -w 100" && stop_tproxy >> /dev/null 2>&1
    iptables="ip6tables -w 100" && stop_tproxy >> /dev/null 2>&1
    iptables="iptables -w 100" && stop_redirect >> /dev/null 2>&1
    log Warn "clean up ip(6)tables transparent proxy rules done."
    enable_ipv6
    log Warn "enable IPv6."
    return 0
    ;;
  renew)
    log Warn "cleaning up ip(6)tables transparent proxy rules."
    iptables="iptables -w 100" && stop_tproxy >> /dev/null 2>&1
    iptables="ip6tables -w 100" && stop_tproxy >> /dev/null 2>&1
    iptables="iptables -w 100" && stop_redirect >> /dev/null 2>&1
    log Warn "clean up ip(6)tables transparent proxy rules done."
    sleep 3
    if ! probe_user_group ; then
      log Error "failed to check Box user group, please make sure ${bin_name} core is started."
      return 1
    fi
    find_packages_uid
    intranet[${#intranet[@]}]=$(ip address | grep -w inet | grep -v 127 | awk '{print $2}')
    if [ "${proxy_method}" = "TPROXY" ] ; then
      if (zcat /proc/config.gz | grep -q TPROXY) ; then
        log Info "use TPROXY:TCP+UDP."
        log Info "creating ip(6)tables transparent proxy rules."
        iptables="iptables -w 100"
        start_tproxy && log Info "create iptables transparent proxy rules done." || (log Error "create iptables transparent proxy rules failed." && stop_tproxy >> /dev/null 2>&1)
        if [ "${ipv6}" = "enable" ] ; then
          log Debug "use IPv6."
          enable_ipv6
          iptables="ip6tables -w 100"
          intranet6[${#intranet6[@]}]=$(ip address | grep -w inet6 | grep -v ::1 | grep -v fe80 | awk '{print $2}')
          start_tproxy && log Info "create ip6tables transparent proxy rules done." || (log Error "create ip6tables transparent proxy rules failed." && stop_tproxy >> /dev/null 2>&1)
        else
          disable_ipv6
          log Warn "disable IPv6."
        fi
      else
        log Warn "the device does not support TPROXY, please switch proxy_method."
        log Info "use REDIRECT:TCP."
        log Info "creating iptables transparent proxy rules."
        iptables="iptables -w 100"
        start_redirect && log Info "create iptables transparent proxy rules done." || (log Error "create iptables transparent proxy rules failed." && stop_redirect >> /dev/null 2>&1)
        [ "${ipv6}" = "enable" ] && enable_ipv6 && log Warn "enable IPv6." || (disable_ipv6 && log Warn "disable IPv6.")
      fi
    else
      [ "${proxy_method}" = "REDIRECT" ] && log Info "use REDIRECT:TCP." || log Info "use MIXED:TCP+TUN."
      log Info "creating iptables transparent proxy rules."
      iptables="iptables -w 100"
      start_redirect && log Info "create iptables transparent proxy rules done." || (log Error "create iptables transparent proxy rules failed." && stop_redirect >> /dev/null 2>&1)
      [ "${ipv6}" = "enable" ] && enable_ipv6 && log Warn "enable IPv6." || (disable_ipv6 && log Warn "disable IPv6.")
    fi
    ;;
  enable_ipv6)
    enable_ipv6
    log Warn "enable IPv6."
    ;;
  disable_ipv6)
    disable_ipv6
    log Warn "disable IPv6."
    ;;
  *)
    log Error "$0 $1 usage: $0 {enable|disable|renew|enable_ipv6|disable_ipv6}"
    ;;
esac
